<?php

include_once 'Config.fitcoders.php';
include_once 'Provider.fitcoders.php';

class Session {

    private $provider;
    private $columns;
    private $params;

    public function __construct() {
        if (!class_exists(Config::$provider)) {
            throw new Exception("El proveedor especificado no ha sido implentado o añadido.");
        }
        $this->provider = new Config::$provider;
        $this->provider->connect();

        if (!$this->provider->isConnected()) {
            /* Controlar error de conexion */
            throw new Exception("NO SE CONECTO CON LA BASE DE DATOS");
        }
    }

    /**
     * Esta es la función llamada por preg_replace_callback() 
     * y que se encarga de devolver el parámetro especificado 
     * para cada interrogante (?) encontrado en la consulta. 
     * Para hacer esto se usa la función next() que va moviendo 
     * el cursor del array para cada coincidencia.
     * @param type $coincidencias
     * @return type
     */
    private function replaceParams($coincidencias) {
        $b = current($this->params);
        next($this->params);
        return $b;
    }

    /**
     * Este método privado es importante, ya que es el que se encarga 
     * de limpiar los parámetros para prevenir errores típicos e insertarlos 
     * en su sitio correspondiente.
     * Para reemplazar se usa una expresión regular mediante la funcion 
     * preg_replace_callback(), que nos permite ejecutar una funcion para 
     * cada coincidencia encontrada. En este caso la callback es replaceParams 
     * (la cual definiremos a continuación).
     * 
     * @param type $sql
     * @param type $params
     * @return type
     */
    private function prepare($sql, $params) {
        for ($i = 0; $i < sizeof($params); $i++) {
            if (is_bool($params[$i])) {
                $params[$i] = $params[$i] ? 1 : 0;
            } elseif (is_double($params[$i]))
                $params[$i] = str_replace(',', '.', $params[$i]);
            elseif (is_numeric($params[$i]))
                $params[$i] = $this->provider->escape($params[$i]);
            elseif (is_null($params[$i]) || empty($params[$i]))
                $params[$i] = "NULL";
            else
                $params[$i] = "'" . $this->provider->escape($params[$i]) . "'";
        }

        $this->params = $params;
        $q = preg_replace_callback("/(\?)/i", array($this, "replaceParams"), $sql);

        return $q;
    }

    /**
     * Este método se encarga de enviar las consultas y comprobar errores:
     * 
     * @param type $q
     * @param type $params
     * @return type
     */
    private function sendQuery($q, $params) {
        $query = $this->prepare($q, $params);
        $result = $this->provider->query($query);

        if ($this->provider->getErrorNo()) {
            /* Controlar errores */
            printf("Error en la consulta");
        }
        return $result;
    }

    /**
     * funcion que vamos a usar públicamente para realizar consultas.
     * Simplemente devuelve la primera columna de la primera fila:
     * 
     * @param type $q
     * @param type $params
     * @return null
     */
    public function executeScalar($q, $params = null) {
        $result = $this->sendQuery($q, $params);
        
        if (strpos(strtoupper($q), 'SELECT') !== FALSE) {
            $this->columns = array();
            $info_campo = $this->provider->fieldsDetail($result);
            $index = 0;
            foreach ($info_campo as $valor) {
                $this->columns[$index] = $valor->name;
                $index = $index + 1;
            }
        }
        if (!is_null($result)) {
            if (!is_object($result)) {
                return $result;
            } else {
                $row = $this->provider->fetchArray($result);
                return $row[0];
            }
        }
        return null;
    }

    public function columns() {
        return $this->columns;
    }

    /**
     * funcion que vamos a usar públicamente para realizar consultas.
     * recorre el resultado cargándolo en un array.
     * 
     * @param type $q
     * @param type $params
     * @return null
     */
    public function execute($q, $params = null) {
        $result = $this->sendQuery($q, $params);
        if (strpos(strtoupper($q), 'SELECT') !== FALSE) {
            $this->columns = array();
            $info_campo = $this->provider->fieldsDetail($result);
            $index = 0;
            foreach ($info_campo as $valor) {
                $this->columns[$index] = $valor->name;
                $index = $index + 1;
            }
        }
        if (is_object($result)) {
            $arr = array();
            while ($row = $this->provider->fetchArray($result)) {
                $arr[] = $row;
            }
            return $arr;
        }
        return null;
    }
    
    public function dataJSON($q, $params = null) {
        $result = $this->sendQuery($q, $params);
        
        if (is_object($result)) {
            return $this->provider->toJSON($result);
        }
        return null;
    }

    /**
     * Cerrando conección, si esta cerrado no hace acción.
     */
    public function closeSession() {
        $this->provider->close();
    }

}
?>

